//
//  myloop.c
//  myloopc
//
//  Created by codew on 7/10/20.
//  Copyright © 2020 codertom. All rights reserved.
//

#include "myloop.h"

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <alsa/asoundlib.h>
#include <signal.h>
#include <pthread.h>

snd_pcm_t *playback_handle, *capture_handle;

#define BUFSIZE (1024)
float buf[BUFSIZE * 4];

static int
alsa_open (snd_pcm_t **alsa_dev, int channels, unsigned samplerate, int realtime,  int dir, const char *device)
//{    const char * device = "default" ;
//    snd_pcm_t *alsa_dev = NULL ;
    snd_pcm_hw_params_t *hw_params ;
    snd_pcm_uframes_t buffer_size ;
    snd_pcm_uframes_t alsa_period_size, alsa_buffer_frames ;
    snd_pcm_sw_params_t *sw_params ;

    int err ;

    if (realtime)
    {    alsa_period_size = 256 ;
        alsa_buffer_frames = 3 * alsa_period_size ;
        }
    else
    {    alsa_period_size = 1024 ;
        alsa_buffer_frames = 4 * alsa_period_size ;
        } ;

    if ((err = snd_pcm_open (&alsa_dev, device, dir, 0)) < 0)
    {    fprintf (stderr, "cannot open audio device \"%s\" (%s)\n", device, snd_strerror (err)) ;
        goto catch_error ;
        } ;

    snd_pcm_nonblock (alsa_dev, 0) ;

    if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0)
    {    fprintf (stderr, "cannot allocate hardware parameter structure (%s)\n", snd_strerror (err)) ;
        goto catch_error ;
        } ;

    if ((err = snd_pcm_hw_params_any (alsa_dev, hw_params)) < 0)
    {    fprintf (stderr, "cannot initialize hardware parameter structure (%s)\n", snd_strerror (err)) ;
        goto catch_error ;
        } ;

    if ((err = snd_pcm_hw_params_set_access (alsa_dev, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
    {    fprintf (stderr, "cannot set access type (%s)\n", snd_strerror (err)) ;
        goto catch_error ;
        } ;

    if ((err = snd_pcm_hw_params_set_format (alsa_dev, hw_params, SND_PCM_FORMAT_FLOAT)) < 0)
    {    fprintf (stderr, "cannot set sample format (%s)\n", snd_strerror (err)) ;
        goto catch_error ;
        } ;

    if ((err = snd_pcm_hw_params_set_rate_near (alsa_dev, hw_params, &samplerate, 0)) < 0)
    {    fprintf (stderr, "cannot set sample rate (%s)\n", snd_strerror (err)) ;
        goto catch_error ;
        } ;

    if ((err = snd_pcm_hw_params_set_channels (alsa_dev, hw_params, channels)) < 0)
    {    fprintf (stderr, "cannot set channel count (%s)\n", snd_strerror (err)) ;
        goto catch_error ;
        } ;

    if ((err = snd_pcm_hw_params_set_buffer_size_near (alsa_dev, hw_params, &alsa_buffer_frames)) < 0)
    {    fprintf (stderr, "cannot set buffer size (%s)\n", snd_strerror (err)) ;
        goto catch_error ;
        } ;

    if ((err = snd_pcm_hw_params_set_period_size_near (alsa_dev, hw_params, &alsa_period_size, 0)) < 0)
    {    fprintf (stderr, "cannot set period size (%s)\n", snd_strerror (err)) ;
        goto catch_error ;
        } ;

    if ((err = snd_pcm_hw_params (alsa_dev, hw_params)) < 0)
    {    fprintf (stderr, "cannot set parameters (%s)\n", snd_strerror (err)) ;
        goto catch_error ;
        } ;

    /* extra check: if we have only one period, this code won't work */
    snd_pcm_hw_params_get_period_size (hw_params, &alsa_period_size, 0) ;
    snd_pcm_hw_params_get_buffer_size (hw_params, &buffer_size) ;
    if (alsa_period_size == buffer_size)
    {    fprintf (stderr, "Can't use period equal to buffer size (%lu == %lu)", alsa_period_size, buffer_size) ;
        goto catch_error ;
        } ;

    snd_pcm_hw_params_free (hw_params) ;

    if ((err = snd_pcm_sw_params_malloc (&sw_params)) != 0)
    {    fprintf (stderr, "%s: snd_pcm_sw_params_malloc: %s", __func__, snd_strerror (err)) ;
        goto catch_error ;
        } ;

    if ((err = snd_pcm_sw_params_current (alsa_dev, sw_params)) != 0)
    {    fprintf (stderr, "%s: snd_pcm_sw_params_current: %s", __func__, snd_strerror (err)) ;
        goto catch_error ;
        } ;

    /* note: set start threshold to delay start until the ring buffer is full */
    snd_pcm_sw_params_current (alsa_dev, sw_params) ;

    if ((err = snd_pcm_sw_params_set_start_threshold (alsa_dev, sw_params, buffer_size)) < 0)
    {    fprintf (stderr, "cannot set start threshold (%s)\n", snd_strerror (err)) ;
        goto catch_error ;
        } ;

    if ((err = snd_pcm_sw_params (alsa_dev, sw_params)) != 0)
    {    fprintf (stderr, "%s: snd_pcm_sw_params: %s", __func__, snd_strerror (err)) ;
        goto catch_error ;
        } ;

    snd_pcm_sw_params_free (sw_params) ;

    snd_pcm_reset (alsa_dev) ;

catch_error :

    if (err < 0 && alsa_dev != NULL)
    {    snd_pcm_close (alsa_dev) ;
        return err ;
    }else if(err < 0 && alsa_dev == NULL){
        return err;
    } ;

//    return alsa_dev ;
    return 0;;
} /* alsa_open */


int main(int argc, char *argv[])
{
    FILE *pFile;
    pFile = fopen("text.pcm", "wb");
    
    int err;
    
    if ((err = alsa_open(&playback_handle, 1, 44100, 0, SND_PCM_STREAM_PLAYBACK, "default")) < 0)
        return err;

    if ((err = alsa_open(&playback_handle, 1, 44100, 0, SND_PCM_STREAM_CAPTURE, "hw:0,0")) < 0)
        return err;

    if ((err = snd_pcm_prepare(playback_handle)) < 0) {
        fprintf(stderr, "cannot prepare audio interface for use(%s)\n",
             snd_strerror(err));
        return err;
    }
    
    if ((err = snd_pcm_start(capture_handle)) < 0) {
        fprintf(stderr, "cannot prepare audio interface for use(%s)\n",
             snd_strerror(err));
        return err;
    }

    memset(buf, 0, sizeof(buf));
    int valueRecording = 0;
    while (valueRecording < 20) {
        int avail;

        if ((err = snd_pcm_wait(playback_handle, 1000)) < 0) {
            fprintf(stderr, "poll failed(%s)\n", strerror(errno));
            break;
        }

        avail = snd_pcm_avail_update(capture_handle);
        if (avail > 0) {
            if (avail > BUFSIZE)
                avail = BUFSIZE;

            snd_pcm_readi(capture_handle, buf, avail);
            printf("Buffer Size: %d \n", avail);
            fwrite(buf, 1, avail*4, pFile);
        }

//        if (signal(SIGINT, stop_recording) == SIG_ERR) {
//            fprintf(stderr, "signal() failed  \n");
//        }
        
//        avail = snd_pcm_avail_update(playback_handle);
//        if (avail > 0) {
//            if (avail > BUFSIZE)
//                avail = BUFSIZE;
//
//            snd_pcm_writei(playback_handle, buf, avail);
//        }
        valueRecording = valueRecording + 1;
        printf("Buffer valueRecording: %d \n", valueRecording);
    }

    snd_pcm_close(playback_handle);
    snd_pcm_close(capture_handle);
    fclose(pFile);
    
    printf("\n CLOSE:::::::::::\n");
    return 0;
}
